home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / AHDI / TTFHDX / IDE.BAK < prev    next >
Encoding:
Text File  |  2001-02-09  |  25.8 KB  |  981 lines

  1. ;+
  2. ; Edit History
  3. ;
  4. ; Sep-05-90    ml.    Created this for drives on the IDE bus.
  5. ;
  6. ; Mar-28-91    ml.    Do not use the IDE Sector Count Register 
  7. ;            to count down mulitiple sectors read or
  8. ;            write.  Some vendors (e.g. Conner and 
  9. ;            Seagate) seem to update this register 
  10. ;            too early, and every now and then, the
  11. ;            last sector of data would remain in the
  12. ;            internal sector buffer.  
  13. ;            
  14. ;            Code in ideread() and idewrite() are modified
  15. ;            not to use the IDE Sector Count Register.
  16. ;
  17. ; Aug-16-91    ml.    W4int() has been modified, in the case of
  18. ;            an error occurred, to return value in the 
  19. ;            Status register for driver code, and return 
  20. ;            value in the Error register for non-driver
  21. ;            code.
  22. ;
  23. ; Oct-10-91    ml.    Special-cased Conner drives for fmtunt() to
  24. ;            set drive to appropiate mode.  Added setmode().
  25. ;
  26. ; Oct-11-91    ml.    Special-cased Conner drives for read and write
  27. ;            to get current drive parameters.  Added gcparm().
  28. ;
  29. ; Mar-03-92    ml.    Added code to test if a drive exist on the IDE bus.
  30. ;
  31. ; Apr-14-92    ml.    For non-BLiTTER transfers, use move.w instead of
  32. ;            move.l, because it's too fast for the drives.
  33. ;-
  34.  
  35. .include    "defs.h"
  36. .include    "sysvar.h"
  37. .include    "mfp.h"
  38. .include    "error.h"
  39. .include    "ide.h"
  40. .include    "blitter.h"
  41.  
  42. .extern    _useblit
  43.  
  44. ;+
  45. ; Wait for status to come back
  46. ;-
  47. w4int:    move.l    #D_WORST,d0    ; d0 = timeout limit
  48.     add.l    _hz_200,d0    ; d0 = expiration time
  49. .0:    btst.b    #5,GPIP        ; interrupt?
  50.     beq.s    .1        ; if so, out of the loop
  51.     cmp.l    _hz_200,d0    ; timeout?
  52.     bhi.s    .0        ; if not, wait some more
  53.     moveq    #$ff,d0        ; else, return timeout
  54.     bra.s    .3
  55. .1:    moveq    #0,d0        ; clear d0
  56.     move.b    IDESR,d0    ; d0.b = status returned
  57.     btst    #ERR,d0        ; any error?
  58.  
  59. .if    !DRIVER            ; for non-driver code
  60.     beq.s    .2        ; if no error, go on
  61.     move.b    IDEER,d0    ; else d0.b = error bits
  62.     bra.s    .3        ; return with error
  63.  
  64. .else                ; for driver code
  65.     bne.s    .3        ; if error, return
  66. .endif    ;!DRIVER
  67.  
  68. .2:    btst    #DRQ,d0        ; else DRQ?
  69.     bne.s    .3        ; if so, just return
  70.     moveq    #0,d0        ; else return OK
  71. .3:    rts            ; return status or error code
  72.  
  73.  
  74.  
  75. ;+
  76. ; ideread() - reads from 1 to 256 sectors as specified in the Task File,
  77. ;        beginning at the specified sector.
  78. ;        - sector count equal to 0 requests 256 sectors.
  79. ;
  80. ; ideread(nhd, nspt, sectnum, count, buf, pdev)
  81. ; WORD    nhd;        4(sp).w        ; # of data heads on pdev
  82. ; WORD    nspt;        6(sp).w        ; # of sectors per track
  83. ; LONG    sectnum;    8(sp).l        ; logical block address
  84. ; WORD    count;        $c(sp).w    ; # of sectors to read
  85. ; BYTE    *buf;        $e(sp).l    ; $f(sp)=high $10(sp)=mid $11(sp)=low
  86. ; WORD    pdev;        $12(sp).w    ; physical device number
  87. ;-
  88.     .globl    _ideread
  89. _ideread:
  90.     bsr    set_dhcs    ; set physical address
  91.     move.l    $e(sp),a0    ; a0 -> buffer to read into
  92.     move.b    $d(sp),IDESC    ; set sector count
  93.  
  94.     move.w    $c(sp),d1    ; d1.w = # of sectors to read
  95.     subq    #1,d1        ; dbra likes one less
  96.  
  97.     tst.b    _useblit    ; BLiTTER exists?
  98.     beq.s    .0        ; if not, don't use it
  99.     moveq    #0,d0        ; else it's a read
  100.     bsr    initblit    ; initialize the BLiTTER
  101.  
  102. .0:    move.b    #0,IDEDOR    ; enable interrupt
  103.     move.b    #READ,IDECR    ; set command code
  104. .1:    bsr    w4int        ; wait for interrupt
  105.     tst.w    d0        ; successful?
  106.     bmi.s    .2        ; if timed-out, return
  107.     btst    #DRQ,d0        ; DRQ?
  108.     beq.s    .2        ; if not, return
  109.                 ; else
  110.     bsr    readbuf        ; transfer data
  111.     dbra    d1,.1        ; go wait for next interrupt
  112.     moveq    #0,d0        ; everything is fine
  113. .2:    rts
  114.  
  115.  
  116. ;+
  117. ; idewrite() - writes from 1 to 256 sectors as specified in the Task File,
  118. ;        beginning at the specified sector.
  119. ;         - sector count equal to 0 requests 256 sectors.
  120. ;
  121. ; idewrite(nhd, nspt, sectnum, count, buf, pdev)
  122. ; WORD    nhd;        4(sp).w        ; # of data heads on pdev
  123. ; WORD    nspt;        6(sp).w        ; # of sectors per track
  124. ; LONG    sectnum;    8(sp).l        ; logical block address
  125. ; WORD    count;        $c(sp).w    ; # sectors to read
  126. ; BYTE    *buf;        $e(sp).l    ; $f(sp)=high $10(sp)=mid $11(sp)=low
  127. ; WORD    pdev;        $12(sp).w    ; physical device number
  128. ;-
  129.     .globl    _idewrite
  130. _idewrite:    
  131.     bsr    set_dhcs    ; set physical address
  132.     move.l    $e(sp),a0    ; a0 -> buffer to write from
  133.     move.b    $d(sp),IDESC    ; set sector count
  134.  
  135.     move.w    $c(sp),d1    ; d1.w = # of sectors to read
  136.     subq    #1,d1        ; dbra likes one less
  137.  
  138.     tst.b    _useblit    ; BLiTTER exists?
  139.     beq.s    .0        ; if not, don't use it
  140.     moveq    #1,d0        ; it's a write
  141.     bsr    initblit    ; initialize the BLiTTER
  142.  
  143. .0:    move.b    #0,IDEDOR    ; enable interrupt
  144.     move.b    #WRITE,IDECR    ; set command code
  145. .1:    btst.b    #DRQ,IDEASR    ; DRQ?
  146.     beq.s    .1        ; if not, wait longer
  147.  
  148. .2:    bsr    wrtbuf        ; transfer data
  149.     bsr    w4int        ; wait for interrupt
  150.     tst.w    d0        ; successful?
  151.     bmi.s    .3        ; if timed-out, return
  152.     btst    #DRQ,d0        ; DRQ?
  153.     beq.s    .3        ; if not, return
  154.     dbra    d1,.2        ; else go transfer data
  155.     moveq    #0,d0        ; everything is fine
  156. .3:    rts
  157.  
  158.  
  159. ;+
  160. ; set_dhcs() - convert a logical block address into a physical address.
  161. ;         - set drive #, head #, cylinder # and sector # in task file.
  162. ;
  163. ; Passed:
  164. ;    8(sp).w = nhd = # of data heads
  165. ;    $a(sp).w = nspt = # of sectors per track
  166. ;    $c(sp).l = logical block address
  167. ;    $16(sp).w = physical unit #
  168. ;-
  169. set_dhcs:
  170.     move.l    $c(sp),d1    ; d1.l = logical block address
  171.     move.w    8(sp),d2    ; d2.w = # of data heads
  172.     move.w    $a(sp),d0    ; d0.w = # of sectors per track
  173.     mulu    d0,d2        ; d2.l = # of sectors per cylinder
  174.                 ;      = # heads * # of sectors per track
  175.     divu.w    d2,d1        ; d1.w = cylinder #
  176.                 ;      = log block addr / #spc
  177.     move.b    d1,IDECL    ; set cylinder low
  178.     lsr.l    #8,d1        ; d1.b = cylinder high
  179.     move.b    d1,IDECH    ; set cylinder high
  180.     lsr.l    #8,d1        ; d1.l = sector # within the cyl
  181.     divu.w    d0,d1        ; d1.w = head #
  182.                 ;      = sector # within cyl / #spt
  183.     move.w    $16(sp),d0    ; d0.w = physical unit #
  184.     andi.b    #7,d0        ; mask off flags from physical unit #
  185.     lsl.b    #4,d0        ; shift unit # to place
  186.     or.b    d0,d1        ; or in drive #
  187. ;+
  188.     or.b    #$a0,d1
  189. ;-
  190.     move.b    d1,IDESDH    ; set drive and head #
  191.     swap    d1        ; d1.w = sector # (base 0)
  192.     addq.w    #1,d1        ;      = sector # + 1 (base 1)
  193.     move.b    d1,IDESN    ; set sector #
  194.     rts
  195.  
  196. ;+
  197. ; identify() - allows the Host to receive parameter information from
  198. ;           the drive.
  199. ;
  200. ; identify(pdev, buf)
  201. ; WORD    pdev;    4(sp).w        ; physical unit #
  202. ; BYTE    *buf;    6(sp).l        ; buffer to put data
  203. ;-
  204.     .globl    _identify
  205. _identify:
  206.     move.w    4(sp),d0    ; d0 = physical unit #
  207.     andi.b    #7,d0        ; mask off flags (if any)
  208.     lsl.b    #4,d0        ; shift unit # to place
  209. ;+
  210.     or.b    #$a0,d0
  211. ;-
  212.     move.b    d0,IDESDH    ; set drive #
  213.     move.l    6(sp),a0    ; a0 -> buffer
  214.  
  215.     tst.b    _useblit    ; BLiTTER exists?
  216.     beq.s    .0        ; if not, no need to init it
  217.     moveq    #0,d0        ; it's a read
  218.     bsr    initblit    ; initialize the BLiTTER
  219.  
  220. .0:    move.b    #0,IDEDOR    ; enable interrupt
  221.     move.b    #IDENTIFY,IDECR    ; set command code
  222.     bsr    w4int        ; wait for interrupt
  223.     tst.w    d0        ; successful?
  224.     bmi.s    .1        ; if timed-out, return
  225.     btst    #DRQ,d0        ; DRQ?
  226.     beq.s    .1        ; if not, return with error
  227.  
  228.     bsr    readbuf        ; read data
  229.     moveq    #0,d0        ; everything is fine
  230. .1:    rts 
  231.  
  232.  
  233. ;+
  234. ; awto() - set drive to Active mode with timeout counter (in 5s increments)
  235. ;
  236. ; awto(pdev, timeout)
  237. ; WORD    pdev;        4(sp).w        ; physical unit #
  238. ; WORD    timeout;    6(sp).w
  239. ;-
  240.     .globl    _awto
  241. _awto:    
  242.     move.w    4(sp),d0    ; d0 = physical unit #
  243.     andi.b    #7,d0        ; mask off flags (if any)
  244.     lsl.b    #4,d0        ; shift unit # to place
  245. ;+
  246.     or.b    #$a0,d0
  247. ;-
  248.     move.b    d0,IDESDH    ; set drive #
  249.     move.b    7(sp),IDESC    ; set timeout counter
  250.     move.b    #AWTO,IDECR    ; set command code
  251.     bra    w4int        ; go wait for interrupt
  252.  
  253.  
  254. ;+
  255. ; readbuf() - reads 512 bytes (128 longs) of data from the sector
  256. ;        buffer.
  257. ;
  258. ; Comments:
  259. ;    A tower of 8 move.l is used to try to speed up the transfer.
  260. ;
  261. ; Passed:
  262. ;    a0.l = buffer to store data read from sector buffer
  263. ;
  264. ;    if BLiTTER code
  265. ;    a1.l = base address of BLiTTER
  266. ;-
  267. readbuf:
  268.     tst.b    _useblit    ; BLiTTER exists?
  269.     beq.s    .0        ; if not, do programmed IO
  270.     move.w    #1,YCNT(a1)    ; one destination line
  271.     move.b    #$80,BUSY(a1)    ; start the BLiTTER
  272.     bsr    restart
  273.     addq.l    #2,DESTADDR(a1)    ; advance to next word of destination
  274.     rts
  275.                 ; Programmed IO
  276. .0:    moveq    #31,d0        ; d0 = (# of words to read / 8) - 1
  277.     lea    IDEDR,a1    ; a1 -> data bus
  278. .1:    move.w    (a1),(a0)+    ; read data from bus
  279.     move.w    (a1),(a0)+    ; read data from bus
  280.     move.w    (a1),(a0)+    ; read data from bus
  281.     move.w    (a1),(a0)+    ; read data from bus
  282.     move.w    (a1),(a0)+    ; read data from bus
  283.     move.w    (a1),(a0)+    ; read data from bus
  284.     move.w    (a1),(a0)+    ; read data from bus
  285.     move.w    (a1),(a0)+    ; read data from bus
  286.     dbra    d0,.1        ; repeat until all done
  287.     rts
  288.  
  289.  
  290. ;+
  291. ; wrtbuf() - writes 512 bytes (128 longs) of data to sector buffer.
  292. ;
  293. ; Passed:
  294. ;    a0.l = buffer with data to write to sector buffer
  295. ;-
  296. wrtbuf:
  297.     tst.b    _useblit    ; BLiTTER exists?
  298.     beq.s    .0        ; if not, do programmed IO
  299.     move.w    #1,YCNT(a1)    ; one destination line
  300.     move.b    #$80,BUSY(a1)    ; start the BLiTTER
  301.     bsr    restart
  302.     addq.l    #2,SRCADDR(a1)    ; advance to next word of source
  303.     rts
  304.                 ; Programmed IO
  305. .0:    moveq    #31,d0        ; d0 = (# longs to write / 8) - 1
  306.     lea    IDEDR,a1    ; a1 -> data bus
  307. .1:    move.w    (a0)+,(a1)    ; write data to bus
  308.     move.w    (a0)+,(a1)    ; write data to bus
  309.     move.w    (a0)+,(a1)    ; write data to bus
  310.     move.w    (a0)+,(a1)    ; write data to bus
  311.     move.w    (a0)+,(a1)    ; write data to bus
  312.     move.w    (a0)+,(a1)    ; write data to bus
  313.     move.w    (a0)+,(a1)    ; write data to bus
  314.     move.w    (a0)+,(a1)    ; write data to bus
  315.     dbra    d0,.1        ;  repeat until all done
  316.     rts
  317.  
  318.  
  319. ;+
  320. ; drvxst() - test if an IDE drive exists
  321. ;
  322. ; Returns:  0 - if drive does not exist
  323. ;        1 - if drive exists
  324. ;-
  325.     .globl    _drvxst
  326. _drvxst:
  327.     move.w    #$5a5a,IDEDR
  328.     move.w    IDEDR,d0
  329.     cmpi.w    #$5a5a,d0
  330.     bne.s    .0
  331.     moveq    #1,d0        ; else, drive exists
  332.     rts
  333. .0:    moveq    #0,d0        ; drive does not exist
  334.     rts
  335.  
  336.  
  337. ;+
  338. ; initblit() - initialize the BLiTTER chip for 512 bytes I/O transfer
  339. ;
  340. ; Passed:
  341. ;    a0.l = destination address if read; source address if write
  342. ;    d0.w = flag to tell whether it's a read or a write
  343. ;-
  344. initblit:
  345.     lea    bBLiTTER,a1        ; a1 -> BLiTTER register map
  346.     tst.b    d0            ; read or write?
  347.     bne.s    ib0            ; (write)
  348.     move.l    #IDEDR,SRCADDR(a1)    ; source addr = IDE data register
  349.     move.l    a0,DESTADDR(a1)        ; destination addr = given buffer
  350.     move.w    #2,DESTXINC(a1)        ; words read
  351.     moveq    #0,d0
  352.     move.w    d0,SRCXINC(a1)        ; never increment source X
  353.     bra.s    ib1
  354.                     ; initialize BLiTTER to write to disk
  355. ib0:    move.l    a0,SRCADDR(a1)        ; source addr = write buffer
  356.     move.l    #IDEDR,DESTADDR(a1)    ; destination addr = IDE data reg
  357.     move.w    #2,SRCXINC(a1)        ; words write
  358.     moveq    #0,d0
  359.     move.w    d0,DESTXINC(a1)        ; never increment destination X
  360.  
  361. ib1:    move.w    d0,SRCYINC(a1)        ; never increment source Y
  362.     move.w    d0,DESTYINC(a1)        ; never increment destination Y
  363.     move.b    d0,SKEW(a1)        ; no skew
  364.     moveq    #$ff,d0
  365.     move.l    d0,ENDMASK1(a1)        ; change all bits at destination
  366.     move.w    d0,ENDMASK3(a1)        ; change all bits at destination
  367.     move.w    #$203,HOP(a1)        ; set HOP and OP to source
  368.     move.w    #256,XCNT(a1)        ; num of words to transfer
  369.     rts
  370.  
  371.  
  372. ;+
  373. ; restart() - restart the BLiTTER
  374. ;
  375. ; Passed:
  376. ;    a1.l = base address of BLiTTER
  377. ;-
  378. restart:
  379.     nop
  380.     tas    BUSY(a1)    ; restart BLiTTER and test if busy
  381.     bmi.s    restart        ; quit if not busy
  382.     rts
  383.  
  384.  
  385. ;+
  386. ; gcparm() - get current drive parameters
  387. ;
  388. ; gcparm(buf)
  389. ; char    *buf;    $4(sp).l    /* -> data returned by identify() */
  390. ;
  391. ; Returns:
  392. ;    d0.w = # of default cylinders
  393. ;    d1.w = # of default heads
  394. ;    d2.w = # of default sectors per track
  395. ;-
  396.     .globl    _gcparm
  397. _gcparm:
  398.     move.l    4(sp),a0    ; a0 -> data buffer
  399.     add.l    #CONMDL,a0    ; a0 -> where Conner model number is
  400.     move.l    a0,-(sp)
  401.     pea    cp2024
  402.     move.w    #6,-(sp)
  403.     bsr    strcmp        ; compare model# with "CP2024"
  404.     adda    #10,sp        ; clean up stack
  405.     tst.w    d0        ; is unit the CP2024 (Kato 20Mb)?
  406.     bne.s    gcp0        ; if not, handle the normal way
  407.                 ; else return default values of CP2024
  408.     move.w    #CP20NCYL,d0    ; d0.w = # of cylinders
  409.     move.w    #CP20NHEAD,d1    ; d1.w = # of heads
  410.     move.w    #CP20NSPT,d2    ; d2.w = # of spt
  411.     bra.s    gcpend
  412.  
  413. gcp0:    move.l    4(sp),a0
  414.     move.w    NCYL(a0),d0    ; d0.w = # of cylinders
  415.     move.w    NHEAD(a0),d1    ; d1.w = # of heads
  416.     move.w    NSPT(a0),d2    ; d2.w = # of sectors per track
  417.  
  418. gcpend:    rts
  419.  
  420.  
  421.  
  422. conner:    dc.b    "Conner",0
  423. .even
  424. cp2024:    dc.b    "CP2024",0
  425. .even
  426.  
  427.  
  428. ;+
  429. ; strcmp() - compare two strings
  430. ;
  431. ; Passed:
  432. ;    4(sp).w  = n (# of bytes to compare)
  433. ;    6(sp).l  = address of first string
  434. ;    10(sp).l = address of second string
  435. ;
  436. ; Returns:
  437. ;    d0.w = 0    if first n bytes of the 2 strings are the same
  438. ;         = non-0    otherwise
  439. ;-
  440. strcmp:    movem.l    d1/a0-a1,-(sp)    ; save registers d1, a0 and a1
  441.     move.w    16(sp),d1    ; d1 = byte count
  442.     subq.w    #1,d1        ; dbra likes one less
  443.     move.l    18(sp),a0    ; a0 -> string 1
  444.     move.l    22(sp),a1    ; a1 -> string 2
  445.     moveq    #1,d0        ; assume strings are not the same
  446. .0:    cmpm.b    (a0)+,(a1)+    ; characters the same?
  447.     bne.s    .1        ; if not, return
  448.     dbra    d1,.0        ; else compare next character
  449.     moveq    #0,d0        ; the strings are the same
  450. .1:    movem.l    (sp)+,d1/a0-a1    ; restore registers d1, a0 and a1
  451.     rts
  452.  
  453.  
  454. .if    !DRIVER
  455.  
  456. ;+
  457. ; recal() - moves the R/W heads from anywhere on the disk to cylinder 0.
  458. ;
  459. ; recal(pdev)
  460. ; WORD    pdev;    $4(sp).w
  461. ;-
  462.     .globl    _recal
  463. _recal:    move.w    4(sp),d0    ; d0 = physical unit #
  464.     andi.b    #7,d0        ; mask off flags (if any)
  465.     lsl.b    #4,d0        ; shift unit # to place
  466. ;+
  467.     or.b    #$a0,d0
  468. ;-
  469.     move.b    d0,IDESDH    ; write drive #
  470.     move.b    #0,IDEDOR    ; enable interrupt
  471.     move.b    #RECAL,IDECR    ; write command code
  472.     bra    w4int        ; go wait for interrupt
  473.  
  474.  
  475. ;+
  476. ; verify() - functions similarly to read() except that no data is
  477. ;         transferred to the host.
  478. ;-
  479.     .globl    _verify
  480. _verify:
  481.     move.w    $e(sp),d0    ; d0.w = physical unit #
  482.     move.l    4(sp),d1    ; d1.l = starting logical sector #
  483.     bsr    set_dhcs    ; set drive#, head#, cylinder# and sector#
  484.     move.l    $a(sp),a0    ; a0 -> buffer to write from
  485.     move.b    9(sp),IDESC    ; set sector count
  486.     move.b    #0,IDEDOR    ; enable interrupt
  487.     move.b    #VERIFY,IDECR    ; set command code
  488. .0:    bsr    w4int        ; wait for interrupt
  489.     bne.s    .1        ; if has error, return
  490.     tst.b    IDESC        ; more to verify?
  491.     bne.s    .0        ; if so, continue
  492.     moveq    #0,d0        ; everything's fine
  493. .1:    rts
  494.  
  495.  
  496. ;+
  497. ; fmtunt() - formats a unit
  498. ;       - always formats sectors as good ones.
  499. ;       - interleave 1:1.
  500. ;
  501. ; fmtunt(pdev)
  502. ; WORD    pdev;    4(sp).w
  503. ;-
  504.     .globl    _fmtunt
  505. _fmtunt:
  506.     movem.l    d3-d6,-(sp)    ; save d3 through d6
  507.     move.w    8(sp),-(sp)    ; set selected unit to the appropiate
  508.     bsr    setmode        ;  mode and get drive parameters in d1-d3
  509.     addq    #2,sp        ; clean up stack
  510.     tst.w    d0        ; setmode() ok?
  511.     bne    .5        ; if not, return
  512.                 ; else fill format data
  513.     bsr    clrsbuf        ; clear scratch buffer
  514.     moveq    #1,d0        ; d0 = sector # (starts with sector 1)
  515.     lea    sbuf,a1        ; a1 -> _identify() data buffer
  516. .0:    move.b    d0,(a1)+    ; set sector #
  517.     clr.b    (a1)+        ; format sector good
  518.     addq.b    #1,d0        ; next sector #
  519.     cmp.b    d0,d3        ; all sector # set?
  520.     bcc.s    .0        ; if not, continue
  521.                 ; format unit
  522.     move.b    d3,d6
  523.     move.w    8(sp),d3    ; d3.w = physical unit #
  524.     andi.b    #7,d3        ; mask off flags (if any)
  525.     lsl.b    #4,d3        ; shift physical unit # into place
  526. ;+
  527.     or.b    #$a0,d3
  528. ;-
  529.     move.b    d3,IDESDH    ; set physical unit #
  530. ;    subq.w    #1,d1        ; dbra likes one less
  531.     move.w    d1,d4        ; d4 = # cylinders
  532. ;    subq.w    #1,d2        ; dbra likes one less
  533.     move.w    d2,d5        ; d5 = # heads
  534. ;    move.w    d2,d3        ; d3 = # heads - 1
  535.     lea    sbuf,a0        ; a0 -> format data
  536.     moveq    #0,d1        ; start with cylinder #0
  537. .1:    
  538.     moveq    #0,d2        ; start with head #0 for current  cylinder
  539. ;    move.w    d3,d2        ; reinitialize head number for next cylinder
  540. .2:    movem.l    d1-d6/a0,-(sp)    ; save cylinder and head count
  541.     move.b    d6,IDESC    ; sector count = # sectors per track
  542.     bsr    _fmttrk        ; format track of current cylinder and head
  543.     bne.s    .4        ; if fail, return
  544. .3:    movem.l    (sp)+,d1-d6/a0    ; restore cylinder and head count
  545.     addq.w    #1,d2        ; next head
  546.     cmp.w    d5,d2        ; done all heads for current cylinder?
  547.     bcs.s    .2        ; if not, format with next head #
  548. ;    dbra    d2,.2        ; for all heads
  549.     addq.w    #1,d1        ; else next cylinder
  550.     cmp.w    d4,d1        ; done all cylinders?
  551.     bcs.s    .1        ; if not, format with next cylinder #
  552. ;    dbra    d1,.1        ; for all cylinders
  553.     moveq    #0,d0        ; everything's fine
  554.     bra.s    .5        ; and return
  555. ;.4:    adda.l    #12,sp        ; else clean up stack
  556. .4:    adda.l    #28,sp        ; else clean up stack
  557. .5:    movem.l    (sp)+,d3-d6    ; restore d3 through d6
  558.     rts
  559.  
  560.  
  561.  
  562. ;+
  563. ; setmode() - set the unit to its default mode and return the default
  564. ;        drive parameters.
  565. ;
  566. ; setmode(pdev)
  567. ; WORD    pdev;    $4(sp).w
  568. ;
  569. ; Returns:
  570. ;    d0.w = 0    if successful
  571. ;         = non-0    if failed
  572. ;    d1.w = # of default cylinders
  573. ;    d2.w = # of default heads
  574. ;    d3.w = # of default sectors per track
  575. ;
  576. ; Comments:
  577. ;    This routine distinguishes the Conner drives from other vendors'
  578. ; because Conner saves their default values in a reserved area. (Sigh)
  579. ; Furthermore, since the default parameters are not stored on the Conner 
  580. ; CP2024 (20Mb) drives at all, they are being hardwired into the code. 
  581. ; (I know, it's terrible!)
  582. ;-
  583. setmode:
  584.     pea    sbuf        ; scratch buffer
  585.     move.w    8(sp),-(sp)    ; physical unit #
  586.     bsr    _identify    ; identify(pdev, buf)
  587.     addq.w    #6,sp        ; clean up stack
  588.     tst.w    d0        ; successful?
  589.     bne    smend        ; if not, return
  590.                 ; else 
  591.     lea    sbuf,a1        ; a1 -> data buffer
  592.     move.l    #sbuf+MDLNUM,-(sp)
  593.     pea    conner
  594.     move.w    #6,-(sp)
  595.     bsr    strcmp        ; compare model# with "Conner"
  596.     adda    #10,sp        ; clean up stack
  597.     tst.w    d0        ; is unit a Conner drive?
  598.     bne.s    other        ; if not, handle the normal way
  599.                 ; else
  600.     move.l    #sbuf+CONMDL,-(sp)
  601.     pea    cp2024
  602.     move.w    #6,-(sp)
  603.     bsr    strcmp        ; compare model# with "CP2024"
  604.     adda    #10,sp        ; clean up stack
  605.     tst.w    d0        ; is unit the CP2024 (Kato 20Mb)?
  606.     bne.s    nkato        ; if not, parms at reserved area
  607.                 ; else return default values of CP2024
  608.     move.w    #CP20NCYL,d1    ; d1.w = # of cylinders
  609.     move.w    #CP20NHEAD,d2    ; d2.w = # of heads
  610.     move.w    #CP20NSPT,d3    ; d3.w = # of spt
  611.     bra.s    smend        ; no need to init parm, just return
  612.  
  613.                 ; for other Conner drives
  614. nkato:    move.w    CPNCYL(a1),d1    ; get parameters at Conner
  615.     moveq    #0,d2        ;   reserved location
  616.     move.b    CPNHEAD(a1),d2
  617.     moveq    #0,d3
  618.     move.b    CPNSPT(a1),d3
  619.     bra.s    sminit        ; go do initparm
  620.  
  621. other:    move.w    NCYL(a1),d1    ; d1.w = # of cylinders
  622.     move.w    NHEAD(a1),d2    ; d2.w = # of heads
  623.     move.w    NSPT(a1),d3    ; d3.w = # of sectors per track
  624.  
  625. sminit:    movem.l    d1-d3,-(sp)    ; save drive parameters
  626.     move.w    d3,-(sp)    ; sectors per track
  627.     move.w    d2,-(sp)    ; # of heads
  628.     move.w    20(sp),-(sp)    ; physical unit #
  629.     bsr    _initparm    ; set drive to default mode
  630.     addq.w    #6,sp        ; clean up stack
  631.     movem.l    (sp)+,d1-d3    ; restore drive parameters
  632.  
  633. smend:    rts
  634.  
  635.  
  636. ;+
  637. ; clrsbuf() - clear the scratch buffer
  638. ;-
  639. clrsbuf:
  640.     movem.l    d0/a0,-(sp)    ; save d0 and a0
  641.     lea    sbuf,a0        ; a0 -> scratch buffer
  642.     move.w    #127,d0        ; d0 = counter
  643. .0:    clr.l    (a0)+        ; clear 4 bytes
  644.     dbra    d0,.0        ; repeat until done
  645.     movem.l    (sp)+,d0/a0    ; restore d0 and a0
  646.     rts
  647.  
  648.  
  649. ;+
  650. ; fmttrk() - formats a track with format data provided.
  651. ;
  652. ; Passed:
  653. ;    d1.w = cylinder #
  654. ;    d2.w = head #
  655. ;    a0.l -> format data
  656. ;-
  657.     .globl    _fmttrk
  658. _fmttrk:
  659.     andi.b    #$f0,IDESDH    ; erase previous head #
  660. ;+
  661.     or.b    #$a0,d2
  662. ;-
  663.     or.b    d2,IDESDH    ; set new head #
  664.     move.b    d1,IDECL    ; set cylinder low
  665.     lsr.w    #8,d1        ; d0.b = cylinder high
  666.     move.b    d1,IDECH    ; set cylinder high
  667.     move.b    #0,IDEDOR    ; enable interrupt
  668.  
  669.     tst.b    _useblit    ; use BLiTTER?
  670.     beq.s    .0        ; if not, no need to init it
  671.     moveq    #1,d0        ; write through BLiTTER
  672.     bsr    initblit    ; initialize the BLiTTER
  673.  
  674. .0:    move.b    #FMTTRK,IDECR    ; set command code
  675. .1:    btst.b    #DRQ,IDEASR    ; DRQ?
  676.     beq.s    .1        ; if not, wait longer
  677.  
  678.     bsr    wrtbuf        ; write format data to sector buffer
  679.     bra    w4int
  680.  
  681.  
  682. ;+
  683. ; seek() - initiates a seek to the track and selects the head 
  684. ;       specified in the Task File.
  685. ;
  686. ; seek(pdev, head, cyl)
  687. ; WORD    pdev;    $4(sp).w
  688. ; WORD    head;    $6(sp).w
  689. ; WORD    cyl;    $8(sp).w
  690. ;-
  691.     .globl    _seek
  692. _seek:    move.w    4(sp),d0    ; d0 = physical unit #
  693.     andi.b    #7,d0        ; mask off flags
  694.     lsl.b    #4,d0        ; shift unit # to place
  695.     or.b    7(sp),d0    ; b4 of d0 = drive #; b3-b0 of d0 = head #;
  696. ;+
  697.     or.b    #$a0,d0
  698. ;-
  699.     move.b    d0,IDESDH    ; set drive and head #
  700.     move.b    #0,IDEDOR    ; enable interrupt
  701.     move.b    9(sp),IDECL    ; set cylinder low
  702.     move.b    8(sp),IDECH    ; set cylinder high
  703.     move.b    #SEEK,IDECR    ; set command code
  704.     bra    w4int        ; go wait for interrupt
  705.  
  706.  
  707. ;+
  708. ; diag() - performs the internal diagnostic tests implemented by 
  709. ;       the drive.
  710. ;-
  711.     .globl    _diag
  712. _diag:    move.b    #0,IDEDOR    ; enable interrupt
  713.     move.b    #DIAG,IDECR    ; set command code
  714.     bra    w4int
  715.  
  716.  
  717. ;+
  718. ; initparm() - enables the host to set the head switch and cylinder
  719. ;           increment points for multiple sector operations.
  720. ;
  721. ; initparm(pdev, head, spt)
  722. ; WORD     pdev;    4(sp).w
  723. ; WORD    head;    6(sp).w
  724. ; WORD    spt;    8(sp).w
  725. ;-
  726.     .globl    _initparm
  727. _initparm:
  728.     move.w    4(sp),d0    ; d0 = physical unit #
  729.     andi.b    #7,d0        ; mask off flags
  730.     lsl.w    #4,d0        ; shift it into place
  731. ;+
  732.     or.b    #$a0,d0
  733. ;-
  734.     move.b    d0,IDESDH    ; set physical unit #
  735.     move.w    6(sp),d0    ; d0 = # of heads
  736.     subq.b    #1,d0        ; maximum head #
  737.     or.b    d0,IDESDH    ; set head #
  738.     moveq    #0,d0
  739.     move.b    d0,IDECL
  740.     move.b    d0,IDECH
  741.     move.b    d0,IDESN
  742.     move.b    9(sp),IDESC    ; set sectors per track
  743.     move.b    #0,IDEDOR    ; enable interrupt
  744.     move.b    #INITPARM,IDECR    ; set command code
  745.     bra    w4int        ; go wait for interrupt
  746.  
  747.  
  748. ;_initparm:
  749. ;    move.w    4(sp),d0    ; d0 = physical unit #
  750. ;    andi.b    #7,d0        ; mask off flags
  751. ;    lsl.w    #4,d0        ; shift it into place
  752. ;    move.b    d0,IDESDH    ; set physical unit #
  753. ;    move.w    6(sp),d0    ; d0 = # of heads
  754. ;    subq.b    #1,d0        ; maximum head #
  755. ;    or.b    d0,IDESDH    ; set head #
  756. ;    move.b    9(sp),IDESC    ; set sectors per track
  757. ;    move.b    #0,IDEDOR    ; enable interrupt
  758. ;    move.b    #INITPARM,IDECR    ; set command code
  759. ;    bra    w4int        ; go wait for interrupt
  760.  
  761.  
  762. ;+
  763. ; rsbuf() - allows the Host to read the current contents of the
  764. ;        drive's sector buffer.
  765. ;
  766. ; rsbuf(pdev, buf)
  767. ; WORD    pdev;    4(sp).w
  768. ; BYTE    *buf;    6(sp).l
  769. ;-
  770.     .globl    _rsbuf
  771. _rsbuf:    move.w    4(sp),d0    ; d0 = physical unit #
  772.     andi.b    #7,d0        ; mask off flags (if any)
  773.     lsl.w    #4,d0        ; shift it into place
  774. ;+
  775.     or.b    #$a0,d0
  776. ;-
  777.     move.b    d0,IDESDH    ; set physical unit #
  778.     move.l    6(sp),a0    ; a0 -> buffer
  779.     move.w    #256,d1
  780.  
  781.     tst.b    _useblit    ; BLiTTER exists?
  782.     beq.s    .0        ; if not, don't use it
  783.     moveq    #0,d0        ; it's a read
  784.     bsr    initblit    ; initialize the BLiTTER
  785.  
  786. .0:    move.b    #0,IDEDOR    ; enable interrupt
  787.     move.b    #RSBUF,IDECR    ; set command code
  788.     bsr    w4int        ; go wait for interrupt
  789.     tst.w    d0        ; successful?
  790.     bmi.s    .1        ; if timed-out, return
  791.     btst    #DRQ,d0        ; DRQ?
  792.     beq.s    .1        ; if not, return with error
  793.  
  794.     bsr    readbuf        ; read data
  795.     moveq    #0,d0        ; everything is fine
  796. .1:    rts 
  797.  
  798.  
  799. ;+
  800. ; wsbuf() - allows the Host to overwrite the contents of the drive's
  801. ;        sector buffer.
  802. ;
  803. ; wsbuf(pdev, buf)
  804. ; WORD    pdev;    4(sp).w
  805. ; BYTE    *buf;    6(sp).l
  806. ;-
  807.     .globl    _wsbuf
  808. _wsbuf:    move.w    4(sp),d0    ; d0 = physical unit #
  809.     andi.b    #7,d0        ; mask off flags (if any)
  810.     lsl.w    #4,d0        ; shift it into place
  811. ;+
  812.     or.b    #$a0,d0
  813. ;-
  814.      move.b    d0,IDESDH    ; set physical unit #
  815.     move.l    6(sp),a0    ; a0 -> buffer
  816.     move.w    #256,d0        ; d0 = word count
  817.  
  818.     tst.b    _useblit    ; BLiTTER exists?
  819.     beq.s    .0        ; if not, don't use it
  820.     moveq    #0,d0        ; it's a read
  821.     bsr    initblit    ; initialize the BLiTTER
  822.  
  823. .0:    move.b    #WSBUF,IDECR    ; set command code
  824. .1:    btst    #DRQ,IDESR    ; DRQ?
  825.     beq.s    .1        ; if not, wait some more
  826.  
  827.     bsr    wrtbuf        ; write data
  828.     moveq    #0,d0        ; everything is fine
  829.     rts
  830.  
  831.  
  832. ;+
  833. ; standby() - set drive to Standby mode
  834. ;
  835. ; standby(pdev)
  836. ; WORD    pdev;    4(sp).w        ; physical unit #
  837. ;-
  838.     .globl    _standby
  839. _standby:
  840.     move.w    4(sp),d0    ; d0 = physical unit #
  841.     andi.b    #7,d0        ; mask off flags (if any)
  842.     lsl.b    #4,d0        ; shift unit # to place
  843. ;+
  844.     or.b    #$a0,d0
  845. ;-
  846.     move.b    d0,IDESDH    ; set drive #
  847.     move.b    #STANDBY,IDECR    ; set command code
  848.     bra    w4int        ; go wait for interrupt
  849.  
  850.  
  851. ;+
  852. ; active() - set drive to Active mode
  853. ;
  854. ; active(pdev)
  855. ; WORD    pdev;    4(sp).w        ; physical unit #
  856. ;-
  857.     .globl    _active
  858. _active:
  859.     move.w    4(sp),d0    ; d0 = physical unit #
  860.     andi.b    #7,d0        ; mask off flags (if any)
  861.     lsl.b    #4,d0        ; shift unit # to place
  862. ;+
  863.     or.b    #$a0,d0
  864. ;-
  865.     move.b    d0,IDESDH    ; set drive #
  866.     move.b    #ACTIVE,IDECR    ; set command code
  867.     bra    w4int        ; go wait for interrupt
  868.  
  869.  
  870. ;+
  871. ; sbwto() - set drive to Standby mode with timeout counter (in 5s increments)
  872. ;
  873. ; sbwto(pdev, timeout)
  874. ; WORD    pdev;        4(sp).w        ; physical unit #
  875. ; WORD    timeout;    6(sp).w
  876. ;-
  877.     .globl    _sbwto
  878. _sbwto:    
  879.     move.w    4(sp),d0    ; d0 = physical unit #
  880.     andi.b    #7,d0        ; mask off flags (if any)
  881.     lsl.b    #4,d0        ; shift unit # to place
  882. ;+
  883.     or.b    #$a0,d0
  884. ;-
  885.     move.b    d0,IDESDH    ; set drive #
  886.     move.b    7(sp),IDESC    ; set timeout counter
  887.     move.b    #SBWTO,IDECR    ; set command code
  888.     bra    w4int        ; go wait for interrupt
  889.  
  890.  
  891. ;+
  892. ; ssc() - set sector count wrt current mode of drive
  893. ;
  894. ; ssc(pdev)
  895. ; WORD    pdev;    4(sp).w        ; physical unit #
  896. ;-
  897.     .globl    _ssc
  898. _ssc:    
  899.     move.w    4(sp),d0    ; d0 = physical unit #
  900.     andi.b    #7,d0        ; mask off flags (if any)
  901.     lsl.b    #4,d0        ; shift unit # to place
  902. ;+
  903.     or.b    #$a0,d0
  904. ;-
  905.     move.b    d0,IDESDH    ; set drive #
  906.     move.b    #SSC,IDECR    ; set command code
  907.     bra    w4int        ; go wait for interrupt
  908.  
  909.  
  910. ;+
  911. ; sbres() - set drive to Standby mode.
  912. ;      - drive will not wake up until reset is sent to drive
  913. ;
  914. ; sbres(pdev)
  915. ; WORD    pdev;    4(sp).w        ; physical unit #
  916. ;-
  917.     .globl    _sbres
  918. _sbres:    
  919.     move.w    4(sp),d0    ; d0 = physical unit #
  920.     andi.b    #7,d0        ; mask off flags (if any)
  921.     lsl.b    #4,d0        ; shift unit # to place
  922. ;+
  923.     or.b    #$a0,d0
  924. ;-
  925.     move.b    d0,IDESDH    ; set drive #
  926.     move.b    #SBRES,IDECR    ; set command code
  927.     bra    w4int        ; go wait for interrupt
  928.  
  929.  
  930. ;+
  931. ; slave() - test if the slave drive exists
  932. ;
  933. ; Returns: 0 - if slave does not exist
  934. ;       1 - if slave exists
  935. ;-
  936.     .globl    _slave
  937. _slave:    moveq    #0,d0        ; assume slave does NOT exist
  938.     bset.b    #4,IDESDH    ; set drive bit to 1 (slave)
  939.     btst.b    #DRDY,IDESR    ; is slave ready?
  940.     beq.s    .0        ; if not, no slave
  941.     moveq    #1,d0        ; else, slave exists
  942. .0:    rts
  943.  
  944.  
  945. ;+
  946. ; _iderdy() - test if the IDE drive is ready
  947. ;
  948. ; Passed:
  949. ;    d0.b = IDE drive unit #
  950. ;
  951. ; Returns: 0 - if drive is NOT ready
  952. ;       1 - if drive is ready
  953. ;-
  954.     .globl    _iderdy
  955. _iderdy:
  956.     andi.b    #7,d0        ; mask off flags (if any)
  957.     lsl.b    #4,d0        ; shift unit # to place
  958. ;+
  959.     or.b    #$a0,d0
  960. ;-
  961.     move.b    d0,IDESDH    ; set drive #
  962.     move.b    #$50,d1        ; ready status
  963.     move.l    #IDERDY,d0    ; set up timer
  964.     add.l    _hz_200,d0
  965. ir0:    cmp.b    IDEASR,d1    ; is drive ready and not busy?
  966.     beq.b    ir1        ; if so, return with drive ready
  967.     cmp.l    _hz_200,d0    ; time-out yet?
  968.     bcc.b    ir0        ; if not, wait longer
  969.     moveq    #0,d0        ; else return drive NOT ready
  970.     rts
  971. ir1:    moveq    #1,d0        ; else, drive is ready
  972.     rts
  973.  
  974.  
  975. .data
  976. sbuf:    dcb.b    512,0        ; scratch buffer
  977.  
  978. .endif    ;!DRIVER
  979.  
  980.  
  981.